﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using Edge.Business.Entities;
using Edge.Business.Managers;
using Edge.Business.Security;
using Edge.Common;
using Edge.Common.Services;
using Edge.Common.Utils;
using Edge.DAL.Common;
using NHibernate;
using NHibernate.Expression;

namespace Edge.DAL.Managers
{
    public class AbstractManager<T, IT, UT> : BaseManager, IAbstractManager<T, IT>
        where UT : UserEntity<int>
    {
        public virtual T Load(IT id)
        {
            T ret;

            using (IDalOperation op = CreateLoadOperation())
            {
                ret = Session.Load<T>(id);
                op.Commit();
            }
            return ret;
        }

        public virtual T LoadCacheble(IT id)
        {
            T ret;

            using (IDalOperation op = CreateLoadOperation())
            {
                ICriteria criteria = CreateCriteria();
                criteria.Add(Expression.Eq("Id", id));
                criteria.SetCacheable(true);
                ret = criteria.UniqueResult<T>();
                op.Commit();
            }

            return ret;
        }

        public virtual void Save(T obj)
        {
            using (IDalOperation op = CreateSaveOperation())
            {
                EntityWithStat<int> helpObj = obj as EntityWithStat<int>;
                if (helpObj != null)
                {
                    if (helpObj.CreatedBy == null)
                        helpObj.CreatedBy = Locator.GetService <IPersonManager<UT>>().GetCurrentAuthor();
                    if (helpObj.CreateDate < DateTime.Parse("01-01-2001"))
                        helpObj.CreateDate = DateTime.Now;
                    helpObj.ModifiedBy = Locator.GetService<IPersonManager<UT>>().GetCurrentAuthor();
                    helpObj.ModifyDate = DateTime.Now;
                    Session.SaveOrUpdate(helpObj);
                }
                else
                {
                    Session.SaveOrUpdate(obj);
                }
                op.Commit();
            }
        }

        public virtual void Update(T obj)
        {
            using (IDalOperation op = CreateSaveOperation())
            {
                Session.Save(obj);
                op.Commit();
            }
        }

        public virtual void Delete(T obj)
        {
            using (IDalOperation op = CreateSaveOperation())
            {
                Session.Delete(obj);
                op.Commit();
            }
        }

        public void Refresh(T obj)
        {
            using (IDalOperation op = CreateLoadOperation())
            {
                Session.Refresh(obj);
                op.Commit();
            }
        }

        public virtual ICollection<T> FindAll()
        {
            return FindAll(false);
        }

        public virtual ICollection<T> FindAll(bool cacheble)
        {
            IList<T> ret = null;
            using (IDalOperation op = CreateLoadOperation())
            {
                ICriteria criteria = CreateCriteria();
                if (cacheble)
                    criteria.SetCacheable(true);
                ret = criteria.List<T>();
                op.Commit();
            }
            return ret;
        }

        protected ICriteria CreateCriteria(FetchOptions fetchOptions)
        {
            ICriteria criteria = Session.CreateCriteria(typeof(T));

            criteria = criteria.SetFirstResult(fetchOptions.FirstResult);
            if (fetchOptions.MaxResults > 0)
                criteria = criteria.SetMaxResults(fetchOptions.MaxResults);
            if (!StringUtils.IsBlankOrNull(fetchOptions.SortExpression))
            {
                SetupSortOptions(criteria, fetchOptions);
            }
            return criteria;
        }

        protected virtual void SetupSortOptions(ICriteria criteria, FetchOptions fetchOptions)
        {
            Order order = fetchOptions.SortDirection == SortDirection.Ascending ?
                                                                                    Order.Asc(fetchOptions.SortExpression) :
                                                                                                                               Order.Desc(fetchOptions.SortExpression);

            criteria = criteria.AddOrder(order);
        }

        protected ICriteria CreateCriteria()
        {
            ICriteria criteria = Session.CreateCriteria(typeof(T));
            return criteria;
        }

        protected ISQLQuery CreateSQLQuery(string queryString)
        {
            ISQLQuery criteria = Session.CreateSQLQuery(queryString);
            return criteria;
        }



        #region Find/Count

        public ICollection<T> Find(FetchOptions fetchOptions)
        {
            IList result;
            using (IDalOperation op = CreateLoadOperation())
            {
                result = CreateCriteria(fetchOptions).List();
                op.Commit();
            }
            return CollectionsUtils.CreateList<T>(result);
        }

        public int Count()
        {
            ICriteria criteria = CreateCriteria();
            criteria.SetProjection(Projections.RowCount());
            return (int)criteria.List()[0];
        }

        #endregion

        protected int GetCount(ICriteria criteria)
        {
            criteria.SetProjection(Projections.RowCount());
            return (int)criteria.List()[0];
        }

        public class AbstractComparer : IEqualityComparer<T>
        {
            public bool Equals(T x, T y)
            {
                return true;
            }

            public int GetHashCode(T obj)
            {
                return obj.GetHashCode();
            }
        }

    }



    


}